/**
 * oCanvas
 * @see http://ocanvas.org/docs/Animation/animate
 */
import oCanvas from 'ocanvas';
import {resMap} from "@/utils/map-res";

/** --- 基本对象信息 --- */
let _dpr = 0;
let _elObj = {};
let _elWidth = 0;
let _elHeight = 0;
let _boardImg = '';
let _gameMap = [];
let _ctxObjs = {};
let _chessBox = {};
let _elCacheMap = new Map();
let _imageCacheMap = new Map();

/** --- 棋盘数值信息 --- */
// 棋子个数
const _chessCount = 15;
// 单个棋子的宽度
let _chessSize = 0;
// 棋盘两边余留的空隙
let _topSpan = 0;
let _leftSpan = 0;

// 原素材宽度
const _originBoardImgWidth = 535;
// 原素材边宽(若两条边不相同，则需要两个变量处理)
const _originBoardSpanWidth = 22;

/**
 * 绑定对象
 * @param el div(此节点承载canvas)
 * @param gameMap 地图对象 @see map-res.js
 * @param boardImg 棋盘图片
 */
export const initBinds = (el, gameMap, boardImg = resMap.get('board')) => {
  // 计算窗口大小
  resizeWindow(el);
  // 初始化canvas
  initCanvas(el);
  // 初始化棋盘
  // initBoard(boardImg);
  // 绘制地图
  initMap(gameMap);
  // 监听窗口大小变化
  listenResize();
}

/**
 * 初始化背景
 * @param imgUrl
 */
export const initBoard = (imgUrl) => {
  const {mapCtx} = _ctxObjs;
  loadImage(imgUrl).then(img => {
    mapCtx.background.set({
      value: img,
      type: 'image'
    })
    mapCtx.redraw();
  });
  _boardImg = imgUrl;
}

/**
 * 初始化地图(完全替换地图数据)
 * @param gameMap
 */
export const initMap = (gameMap = []) => {
  const {mapCtx} = _ctxObjs;
  mapCtx.reset();
  _elCacheMap.clear();
  _imageCacheMap.clear();

  gameMap.map((chess) => {
    const {mapCtx} = _ctxObjs;
    loadImage(chess.id).then(img => {
      const displayImage = mapCtx.display.image({
        x: _chessSize * chess.y + _leftSpan,
        y: _chessSize * chess.x + _topSpan,
        image: img,
        width: _chessSize,
        height: _chessSize,
        opacity: 0.8,
        zIndex: 'back',
      });
      _elCacheMap.set(chess.id, displayImage);
      mapCtx.addChild(displayImage, false);
      displayImage.fadeIn("short", "linear", () => mapCtx.redraw());
    });
  })
  // 保存棋盘，方便在界面大小变化时重绘
  _gameMap = gameMap;
}

/**
 * 设置棋子盒子
 * @param chessBox
 */
export const setChessBox = (chessBox) => {
  const {boxCtx} = _ctxObjs;
  boxCtx.reset();
  if (chessBox && chessBox.show) {
    // 绘制盒子
    loadImage('box').then(img => {
      const displayImage = boxCtx.display.image({
        x: _chessSize * chessBox.y + _leftSpan,
        y: _chessSize * chessBox.x + _topSpan,
        image: img,
        width: _chessSize,
        height: _chessSize,
      });
      boxCtx.addChild(displayImage);
    });
    _chessBox = chessBox;
  }
}

/**
 * 添加棋子
 * @param chess
 * @param gameMap
 */
export const moveChess = (chess, gameMap) => {
  loadImage(chess.id).then(img => {
    const {mapCtx} = _ctxObjs;
    const displayImage = mapCtx.display.image({
      x: _chessSize * chess.y + _leftSpan,
      y: _chessSize * chess.x + _topSpan,
      image: img,
      width: _chessSize,
      height: _chessSize,
      opacity: 0.8,
      zIndex: 'back',
    });
    _elCacheMap.set(chess.id, displayImage);
    mapCtx.addChild(displayImage, false);
    displayImage.fadeIn("short", "linear", () => mapCtx.redraw());
  })
  _gameMap = gameMap;
}

/**
 * 删除节点
 * @param chessId
 */
export const removeChess = (chessId) => {
  const {mapCtx} = _ctxObjs;
  const delObj = _elCacheMap.get(chessId);
  if (delObj) {
    delObj.fadeOut("short", "linear", () => {
      _elCacheMap.delete(chessId);
      mapCtx.removeChild(delObj);
    });
  }
}

/**
 * 监听窗口大小变动
 */
const listenResize = () => {
  window.addEventListener('resize', e => {
    // 计算窗口大小
    resizeWindow(_elObj);
    // 初始化canvas
    initCanvas(_elObj);
    // 初始化棋盘
    // initBoard(_boardImg);
    // 绘制地图
    resizeMap(_gameMap);
    // 设置box
    setChessBox(_chessBox);
  });
}

/**
 * @param el div(此节点承载canvas)
 */
const resizeWindow = el => {
  _elObj = el;
  _elWidth = el.clientWidth;
  _elHeight = el.clientHeight;
  _dpr = window.devicePixelRatio || 1;
  // 根据素材的原宽算出要缩放的比例
  const scale = _originBoardImgWidth / _elWidth;
  // 根据比例和原素材的边宽算出当前分辨率下边宽值
  const scaleSpan = _originBoardSpanWidth / scale;
  // dpr后的宽度
  const dprWidth = _elWidth * _dpr - scaleSpan;
  // 单个棋子的宽度
  const chessSize = dprWidth / _chessCount;
  // 余宽分摊给两条边
  _topSpan = scaleSpan / 2;
  _leftSpan = scaleSpan / 2;
  _chessSize = chessSize;
}

/**
 * 加载图片
 * @param id
 */
const loadImage = id => {
  return new Promise((resolve, reject) => {
    try {
      if (_imageCacheMap.has(id)) {
        resolve(_imageCacheMap.get(id));
      } else {
        const drawImg = new Image();
        drawImg.src = resMap.get(id) || id;
        drawImg.onload = e => {
          _imageCacheMap.set(id, drawImg);
          resolve(drawImg);
        }
      }
    } catch (e) {
      reject(e);
    }
  })
}

/**
 * 重新设置地图大小
 * @param gameMap
 */
const resizeMap = (gameMap) => {
  const {mapCtx} = _ctxObjs;
  _elCacheMap.clear();
  gameMap.map(chess => {
    // 重新设置地图大小不会带任何动画
    loadImage(chess.id).then(img => {
      const displayImage = mapCtx.display.image({
        x: _chessSize * chess.y + _leftSpan,
        y: _chessSize * chess.x + _topSpan,
        image: img,
        width: _chessSize,
        height: _chessSize,
        zIndex: 'back',
      });
      mapCtx.addChild(displayImage);
      _elCacheMap.set(chess.id, displayImage);
    });
  });
  _gameMap = gameMap;
}

/**
 * 初始化canvas节点
 * @param el
 */
const initCanvas = (el) => {
  el.innerHTML = '';
  // 销毁实例
  destroyAllCtx();

  const mapCanvas = document.createElement('canvas');
  mapCanvas.style.width = `${_elWidth}px`;
  mapCanvas.style.height = `${_elHeight}px`;
  mapCanvas.style.position = 'absolute';
  mapCanvas.style.zIndex = '2';
  mapCanvas.style.top = '0';
  mapCanvas.style.left = '0';
  mapCanvas.id = 'mapCanvas';
  mapCanvas.width = _elWidth * _dpr;
  mapCanvas.height = _elHeight * _dpr;

  const boxCanvas = document.createElement('canvas');
  boxCanvas.style.width = `${_elWidth}px`;
  boxCanvas.style.height = `${_elHeight}px`;
  boxCanvas.style.position = 'absolute';
  boxCanvas.style.zIndex = '1';
  boxCanvas.style.top = '0';
  boxCanvas.style.left = '0';
  boxCanvas.id = 'boxCanvas';
  boxCanvas.width = _elWidth * _dpr;
  boxCanvas.height = _elHeight * _dpr;

  el.appendChild(mapCanvas);
  el.appendChild(boxCanvas);

  const mapCtx = oCanvas.create({
    canvas: "#mapCanvas",
    fps: 30,
  });

  const boxCtx = oCanvas.create({
    canvas: "#boxCanvas",
    fps: 30,
  });


  _ctxObjs = {mapCtx, boxCtx};
}

/**
 * 销毁实例(如果有)
 */
const destroyAllCtx = () => {
  const {mapCtx, boxCtx} = _ctxObjs;
  mapCtx && mapCtx.destroy();
  boxCtx && mapCtx.destroy();
}
